package com.youyou.lambdaTest;

import com.google.common.collect.Lists;
import lombok.Data;
import org.junit.Before;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author:Lau
 * @create: 2023-01-31 14:31
 * @Description: 分组测试
 */
public class GroupingBy {

    List<Product> prodList = new ArrayList<Product>();

    @Before
    public void init() {
        Product prod1 = new Product(1L, 1, new BigDecimal("15.5"), "面包", "零食");
        Product prod2 = new Product(2L, 2, new BigDecimal("20"), "饼干", "零食");
        Product prod3 = new Product(3L, 3, new BigDecimal("30"), "月饼", "零食");
        Product prod4 = new Product(4L, 3, new BigDecimal("10"), "青岛啤酒", "啤酒");
        Product prod5 = new Product(5L, 10, new BigDecimal("15"), "百威啤酒", "啤酒");
        //prodList = Lists.newArrayList(prod1, prod2, prod3, prod4, prod5);
        prodList = Stream.of(prod1, prod2, prod3, prod4, prod5).collect(Collectors.toList());
        System.out.println("--------------------原始数据--------------------");
        prodList.forEach(System.out::println);
        System.out.println("--------------------原始数据--------------------");
    }

    /**
     * 按照类目分组
     */
    @Test
    public void test1() {
        Map<String, List<Product>> prodMap= prodList.stream().collect(Collectors.groupingBy(Product::getCategory));
        System.out.println(prodMap);
    }

    /**
     * 按照几个属性拼接分组
     */
    @Test
    public void test2() {
        Map<String, List<Product>> prodMap = prodList.stream()
                .collect(Collectors.groupingBy(item -> item.getCategory() + "_" + item.getName()));
        System.out.println(prodMap);
    }

    /**
     * 根据不同条件分组
     */
    @Test
    public void test3() {
        Map<String, List<Product>> prodMap= prodList.stream().collect(Collectors.groupingBy(item -> {
            if(item.getNum() < 3) {
                return "3";
            }else {
                return "other";
            }
        }));
        System.out.println(prodMap);
    }

    /**
     * 多级分组
     * 要实现多级分组，我们可以使用一个由双参数版本的Collectors.groupingBy工厂方法创 建的收集器，
     * 它除了普通的分类函数之外，还可以接受collector类型的第二个参数。那么要进 行二级分组的话，
     * 我们可以把一个内层groupingBy传递给外层groupingBy，并定义一个为流 中项目分类的二级标准。
     */
    @Test
    public void test4() {
        Map<String, Map<String, List<Product>>> prodMap= prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.groupingBy(item -> {
            if(item.getNum() < 3) {
                return "3";
            }else {
                return "other";
            }
        })));
        System.out.println(prodMap);
    }

    /**
     * 按子组收集数据
     */
    @Test
    public void test5() {
        Map<String, Long> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.counting()));
        System.out.println(prodMap);
    }

    /**
     * 求和
     */
    @Test
    public void test6() {
        Map<String, Integer> prodMap = prodList.stream()
                .collect(Collectors.groupingBy(Product::getCategory, Collectors.summingInt(Product::getNum)));

        System.out.println(prodMap);
    }

    /**
     * 把收集器的结果转换为另一种类型
     */
    @Test
    public void test7() {
        Map<String, Product> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory,
                Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Product::getNum)),
                        Optional::get)));

        System.out.println(prodMap);
    }

    /**
     * 联合其他收集器
     */
    @Test
    public void test8() {
        Map<String, Set<String>> prodMap = prodList.stream().collect(
                Collectors.groupingBy(Product::getCategory, Collectors.mapping(Product::getName, Collectors.toSet())));
        System.out.println(prodMap);
    }


















    @Data
    public class Product{
        Long id;
        Integer num;
        BigDecimal price;
        String name;
        String category;
        public Product(Long id, Integer num, BigDecimal price, String name, String category) {
            this.id = id;
            this.num = num;
            this.price = price;
            this.name = name;
            this.category = category;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("Product{");
            sb.append("id=").append(id);
            sb.append(", num=").append(num);
            sb.append(", price=").append(price);
            sb.append(", name='").append(name).append('\'');
            sb.append(", category='").append(category).append('\'');
            sb.append('}').append("\n");
            return sb.toString();
        }
    }
}
